#include "wx/wxprec.h"
#include "wx/event.h"

#if wxUSE_BASE
#include "wx/ptr_scpd.h"

wxDECLARE_SCOPED_PTR( wxEvent, wxEventPtr )
wxDEFINE_SCOPED_PTR( wxEvent, wxEventPtr )
#endif // wxUSE_BASE

#if wxUSE_BASE
IMPLEMENT_DYNAMIC_CLASS( wxEvtHandler, wxObject )
IMPLEMENT_ABSTRACT_CLASS( wxEvent, wxObject )
#endif

#if wxUSE_GUI

IMPLEMENT_DYNAMIC_CLASS( wxIdleEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxCommandEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxNotifyEvent, wxCommandEvent )
IMPLEMENT_DYNAMIC_CLASS( wxScrollEvent, wxCommandEvent )
IMPLEMENT_DYNAMIC_CLASS( wxScrollWinEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxMouseEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxKeyEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxSizeEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxPaintEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxNcPaintEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxEraseEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxMoveEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxFocusEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxChildFocusEvent, wxCommandEvent )
IMPLEMENT_DYNAMIC_CLASS( wxCloseEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxShowEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxMaximizeEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxIconizeEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxMenuEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxJoystickEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxDropFilesEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxActivateEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxInitDialogEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxSetCursorEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxSysColourChangedEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxDisplayChangedEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxUpdateUIEvent, wxCommandEvent )
IMPLEMENT_DYNAMIC_CLASS( wxNavigationKeyEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxPaletteChangedEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxQueryNewPaletteEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxWindowCreateEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxWindowDestroyEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxHelpEvent, wxCommandEvent )
IMPLEMENT_DYNAMIC_CLASS( wxContextMenuEvent, wxCommandEvent )
IMPLEMENT_DYNAMIC_CLASS( wxMouseCaptureChangedEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxMouseCaptureLostEvent, wxEvent )
IMPLEMENT_DYNAMIC_CLASS( wxClipboardTextEvent, wxCommandEvent )
#endif

#if wxUSE_BASE

const wxEventTable *wxEvtHandler::GetEventTable() const {
  return &wxEvtHandler::sm_eventTable;
}

const wxEventTable wxEvtHandler::sm_eventTable = {
  ( const wxEventTable * )NULL, &wxEvtHandler::sm_eventTableEntries[0]
};

wxEventHashTable &wxEvtHandler::GetEventHashTable() const {
  return wxEvtHandler::sm_eventHashTable;
}

wxEventHashTable wxEvtHandler::sm_eventHashTable( wxEvtHandler::sm_eventTable );
const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = {
  DECLARE_EVENT_TABLE_ENTRY( wxEVT_NULL, 0, 0, ( wxObjectEventFunction )NULL, NULL )
};


#ifdef __WXDEBUG__
class wxEventTableEntryModule: public wxModule {
    DECLARE_DYNAMIC_CLASS( wxEventTableEntryModule )
  public:
    wxEventTableEntryModule() {}
    bool OnInit() {
      wxEventHashTable::ReconstructAll();
      return true;
    }
    void OnExit() {
      wxEventHashTable::ClearAll();
    }
};
IMPLEMENT_DYNAMIC_CLASS( wxEventTableEntryModule, wxModule )
#endif

wxList *wxPendingEvents = ( wxList * )NULL;

#if wxUSE_THREADS
wxCriticalSection *wxPendingEventsLocker = ( wxCriticalSection * )NULL;
#endif

#if !WXWIN_COMPATIBILITY_EVENT_TYPES

const wxEventType wxEVT_FIRST = 10000;
const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000;

DEFINE_EVENT_TYPE( wxEVT_NULL )
DEFINE_EVENT_TYPE( wxEVT_IDLE )
DEFINE_EVENT_TYPE( wxEVT_SOCKET )

#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES

#endif // wxUSE_BASE

#if wxUSE_GUI

#if !WXWIN_COMPATIBILITY_EVENT_TYPES

DEFINE_EVENT_TYPE( wxEVT_COMMAND_BUTTON_CLICKED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_CHECKBOX_CLICKED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_CHOICE_SELECTED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_LISTBOX_SELECTED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_CHECKLISTBOX_TOGGLED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_MENU_SELECTED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_SLIDER_UPDATED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_RADIOBOX_SELECTED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_RADIOBUTTON_SELECTED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_SCROLLBAR_UPDATED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_VLBOX_SELECTED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_COMBOBOX_SELECTED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_TOOL_RCLICKED )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_TOOL_ENTER )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_SPINCTRL_UPDATED )
DEFINE_EVENT_TYPE( wxEVT_TIMER )
DEFINE_EVENT_TYPE( wxEVT_LEFT_DOWN )
DEFINE_EVENT_TYPE( wxEVT_LEFT_UP )
DEFINE_EVENT_TYPE( wxEVT_MIDDLE_DOWN )
DEFINE_EVENT_TYPE( wxEVT_MIDDLE_UP )
DEFINE_EVENT_TYPE( wxEVT_RIGHT_DOWN )
DEFINE_EVENT_TYPE( wxEVT_RIGHT_UP )
DEFINE_EVENT_TYPE( wxEVT_MOTION )
DEFINE_EVENT_TYPE( wxEVT_ENTER_WINDOW )
DEFINE_EVENT_TYPE( wxEVT_LEAVE_WINDOW )
DEFINE_EVENT_TYPE( wxEVT_LEFT_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_MIDDLE_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_RIGHT_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_SET_FOCUS )
DEFINE_EVENT_TYPE( wxEVT_KILL_FOCUS )
DEFINE_EVENT_TYPE( wxEVT_CHILD_FOCUS )
DEFINE_EVENT_TYPE( wxEVT_MOUSEWHEEL )
DEFINE_EVENT_TYPE( wxEVT_NC_LEFT_DOWN )
DEFINE_EVENT_TYPE( wxEVT_NC_LEFT_UP )
DEFINE_EVENT_TYPE( wxEVT_NC_MIDDLE_DOWN )
DEFINE_EVENT_TYPE( wxEVT_NC_MIDDLE_UP )
DEFINE_EVENT_TYPE( wxEVT_NC_RIGHT_DOWN )
DEFINE_EVENT_TYPE( wxEVT_NC_RIGHT_UP )
DEFINE_EVENT_TYPE( wxEVT_NC_MOTION )
DEFINE_EVENT_TYPE( wxEVT_NC_ENTER_WINDOW )
DEFINE_EVENT_TYPE( wxEVT_NC_LEAVE_WINDOW )
DEFINE_EVENT_TYPE( wxEVT_NC_LEFT_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_NC_MIDDLE_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_NC_RIGHT_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_CHAR )
DEFINE_EVENT_TYPE( wxEVT_CHAR_HOOK )
DEFINE_EVENT_TYPE( wxEVT_NAVIGATION_KEY )
DEFINE_EVENT_TYPE( wxEVT_KEY_DOWN )
DEFINE_EVENT_TYPE( wxEVT_KEY_UP )
#if wxUSE_HOTKEY
DEFINE_EVENT_TYPE( wxEVT_HOTKEY )
#endif

DEFINE_EVENT_TYPE( wxEVT_SET_CURSOR )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_TOP )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_BOTTOM )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_LINEUP )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_LINEDOWN )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_PAGEUP )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_PAGEDOWN )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_THUMBTRACK )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_THUMBRELEASE )
DEFINE_EVENT_TYPE( wxEVT_SCROLL_CHANGED )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_TOP )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_BOTTOM )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_LINEUP )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_LINEDOWN )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_PAGEUP )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_PAGEDOWN )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_THUMBTRACK )
DEFINE_EVENT_TYPE( wxEVT_SCROLLWIN_THUMBRELEASE )
DEFINE_EVENT_TYPE( wxEVT_SIZE )
DEFINE_EVENT_TYPE( wxEVT_SIZING )
DEFINE_EVENT_TYPE( wxEVT_MOVE )
DEFINE_EVENT_TYPE( wxEVT_MOVING )
DEFINE_EVENT_TYPE( wxEVT_CLOSE_WINDOW )
DEFINE_EVENT_TYPE( wxEVT_END_SESSION )
DEFINE_EVENT_TYPE( wxEVT_QUERY_END_SESSION )
DEFINE_EVENT_TYPE( wxEVT_HIBERNATE )
DEFINE_EVENT_TYPE( wxEVT_ACTIVATE_APP )
DEFINE_EVENT_TYPE( wxEVT_POWER )
DEFINE_EVENT_TYPE( wxEVT_ACTIVATE )
DEFINE_EVENT_TYPE( wxEVT_CREATE )
DEFINE_EVENT_TYPE( wxEVT_DESTROY )
DEFINE_EVENT_TYPE( wxEVT_SHOW )
DEFINE_EVENT_TYPE( wxEVT_ICONIZE )
DEFINE_EVENT_TYPE( wxEVT_MAXIMIZE )
DEFINE_EVENT_TYPE( wxEVT_MOUSE_CAPTURE_CHANGED )
DEFINE_EVENT_TYPE( wxEVT_MOUSE_CAPTURE_LOST )
DEFINE_EVENT_TYPE( wxEVT_PAINT )
DEFINE_EVENT_TYPE( wxEVT_ERASE_BACKGROUND )
DEFINE_EVENT_TYPE( wxEVT_NC_PAINT )
DEFINE_EVENT_TYPE( wxEVT_PAINT_ICON )
DEFINE_EVENT_TYPE( wxEVT_MENU_OPEN )
DEFINE_EVENT_TYPE( wxEVT_MENU_CLOSE )
DEFINE_EVENT_TYPE( wxEVT_MENU_HIGHLIGHT )
DEFINE_EVENT_TYPE( wxEVT_CONTEXT_MENU )
DEFINE_EVENT_TYPE( wxEVT_SYS_COLOUR_CHANGED )
DEFINE_EVENT_TYPE( wxEVT_DISPLAY_CHANGED )
DEFINE_EVENT_TYPE( wxEVT_SETTING_CHANGED )
DEFINE_EVENT_TYPE( wxEVT_QUERY_NEW_PALETTE )
DEFINE_EVENT_TYPE( wxEVT_PALETTE_CHANGED )
DEFINE_EVENT_TYPE( wxEVT_JOY_BUTTON_DOWN )
DEFINE_EVENT_TYPE( wxEVT_JOY_BUTTON_UP )
DEFINE_EVENT_TYPE( wxEVT_JOY_MOVE )
DEFINE_EVENT_TYPE( wxEVT_JOY_ZMOVE )
DEFINE_EVENT_TYPE( wxEVT_DROP_FILES )
DEFINE_EVENT_TYPE( wxEVT_DRAW_ITEM )
DEFINE_EVENT_TYPE( wxEVT_MEASURE_ITEM )
DEFINE_EVENT_TYPE( wxEVT_COMPARE_ITEM )
DEFINE_EVENT_TYPE( wxEVT_INIT_DIALOG )
DEFINE_EVENT_TYPE( wxEVT_UPDATE_UI )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_TEXT_COPY )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_TEXT_CUT )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_TEXT_PASTE )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_LEFT_CLICK )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_LEFT_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_RIGHT_CLICK )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_RIGHT_DCLICK )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_SET_FOCUS )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_KILL_FOCUS )
DEFINE_EVENT_TYPE( wxEVT_COMMAND_ENTER )
DEFINE_EVENT_TYPE( wxEVT_HELP )
DEFINE_EVENT_TYPE( wxEVT_DETAILED_HELP )

#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES
#endif

#if wxUSE_BASE

int wxNewEventType() {
  // MT-FIXME
  static int s_lastUsedEventType = wxEVT_FIRST;
  return s_lastUsedEventType++;
}

wxEvent::wxEvent( int theId, wxEventType commandType ) {
  m_eventType = commandType;
  m_eventObject = ( wxObject * ) NULL;
  m_timeStamp = 0;
  m_id = theId;
  m_skipped = false;
  m_callbackUserData = ( wxObject * ) NULL;
  m_isCommandEvent = false;
  m_propagationLevel = wxEVENT_PROPAGATE_NONE;
}

wxEvent::wxEvent( const wxEvent &src )
  : wxObject( src )
  , m_eventObject( src.m_eventObject )
  , m_eventType( src.m_eventType )
  , m_timeStamp( src.m_timeStamp )
  , m_id( src.m_id )
  , m_callbackUserData( src.m_callbackUserData )
  , m_propagationLevel( src.m_propagationLevel )
  , m_skipped( src.m_skipped )
  , m_isCommandEvent( src.m_isCommandEvent ) {
}

#endif // wxUSE_BASE

#if wxUSE_GUI

wxCommandEvent::wxCommandEvent( wxEventType commandType, int theId )
  : wxEvent( theId, commandType ) {
  m_clientData = ( char * ) NULL;
  m_clientObject = ( wxClientData * ) NULL;
  m_extraLong = 0;
  m_commandInt = 0;
  m_isCommandEvent = true;
  m_propagationLevel = wxEVENT_PROPAGATE_MAX;
}

wxString wxCommandEvent::GetString() const {
  if( m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject ) {
    return m_cmdString;
  } else {
    #if wxUSE_TEXTCTRL
    wxTextCtrl *txt = wxDynamicCast( m_eventObject, wxTextCtrl );
    if( txt ) {
      return txt->GetValue();
    } else
    #endif // wxUSE_TEXTCTRL
      return m_cmdString;
  }
}

#if wxUSE_LONGLONG
wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0;
#endif

long wxUpdateUIEvent::sm_updateInterval = 0;

wxUpdateUIMode wxUpdateUIEvent::sm_updateMode = wxUPDATE_UI_PROCESS_ALL;

bool wxUpdateUIEvent::CanUpdate( wxWindowBase *win ) {
  if( win &&
      ( GetMode() == wxUPDATE_UI_PROCESS_SPECIFIED &&
        ( ( win->GetExtraStyle() & wxWS_EX_PROCESS_UI_UPDATES ) == 0 ) ) ) {
    return false;
  }
  if( sm_updateInterval == -1 ) {
    return false;
  }
  if( sm_updateInterval == 0 ) {
    return true;
  }
  #if wxUSE_STOPWATCH && wxUSE_LONGLONG
  wxLongLong now = wxGetLocalTimeMillis();
  if( now > ( sm_lastUpdate + sm_updateInterval ) ) {
    return true;
  }
  return false;
  #else
  return true;
  #endif
}

void wxUpdateUIEvent::ResetUpdateTime() {
  #if wxUSE_STOPWATCH && wxUSE_LONGLONG
  if( sm_updateInterval > 0 ) {
    wxLongLong now = wxGetLocalTimeMillis();
    if( now > ( sm_lastUpdate + sm_updateInterval ) ) {
      sm_lastUpdate = now;
    }
  }
  #endif
}

wxIdleMode wxIdleEvent::sm_idleMode = wxIDLE_PROCESS_ALL;

bool wxIdleEvent::CanSend( wxWindow* win ) {
  if( win &&
      ( GetMode() == wxIDLE_PROCESS_SPECIFIED &&
        ( ( win->GetExtraStyle() & wxWS_EX_PROCESS_IDLE ) == 0 ) ) ) {
    return false;
  }
  return true;
}


wxScrollEvent::wxScrollEvent( wxEventType commandType,
                              int id,
                              int pos,
                              int orient )
  : wxCommandEvent( commandType, id ) {
  m_extraLong = orient;
  m_commandInt = pos;
}

wxScrollWinEvent::wxScrollWinEvent( wxEventType commandType,
                                    int pos,
                                    int orient ) {
  m_eventType = commandType;
  m_extraLong = orient;
  m_commandInt = pos;
}

wxMouseEvent::wxMouseEvent( wxEventType commandType ) {
  m_eventType = commandType;
  m_metaDown = false;
  m_altDown = false;
  m_controlDown = false;
  m_shiftDown = false;
  m_leftDown = false;
  m_rightDown = false;
  m_middleDown = false;
  m_x = 0;
  m_y = 0;
  m_wheelRotation = 0;
  m_wheelDelta = 0;
  m_linesPerAction = 0;
}

void wxMouseEvent::Assign( const wxMouseEvent& event ) {
  m_eventType = event.m_eventType;
  m_x = event.m_x;
  m_y = event.m_y;
  m_leftDown = event.m_leftDown;
  m_middleDown = event.m_middleDown;
  m_rightDown = event.m_rightDown;
  m_controlDown = event.m_controlDown;
  m_shiftDown = event.m_shiftDown;
  m_altDown = event.m_altDown;
  m_metaDown = event.m_metaDown;
  m_wheelRotation = event.m_wheelRotation;
  m_wheelDelta = event.m_wheelDelta;
  m_linesPerAction = event.m_linesPerAction;
}

bool wxMouseEvent::ButtonDClick( int but ) const {
  switch( but ) {
    default:
      wxFAIL_MSG( wxT( "invalid parameter in wxMouseEvent::ButtonDClick" ) );
    case wxMOUSE_BTN_ANY:
      return ( LeftDClick() || MiddleDClick() || RightDClick() );
    case wxMOUSE_BTN_LEFT:
      return LeftDClick();
    case wxMOUSE_BTN_MIDDLE:
      return MiddleDClick();
    case wxMOUSE_BTN_RIGHT:
      return RightDClick();
  }
}

bool wxMouseEvent::ButtonDown( int but ) const {
  switch( but ) {
    default:
      wxFAIL_MSG( wxT( "invalid parameter in wxMouseEvent::ButtonDown" ) );
    // fall through
    case wxMOUSE_BTN_ANY:
      return ( LeftDown() || MiddleDown() || RightDown() );
    case wxMOUSE_BTN_LEFT:
      return LeftDown();
    case wxMOUSE_BTN_MIDDLE:
      return MiddleDown();
    case wxMOUSE_BTN_RIGHT:
      return RightDown();
  }
}

bool wxMouseEvent::ButtonUp( int but ) const {
  switch( but ) {
    default:
      wxFAIL_MSG( wxT( "invalid parameter in wxMouseEvent::ButtonUp" ) );
    // fall through
    case wxMOUSE_BTN_ANY:
      return ( LeftUp() || MiddleUp() || RightUp() );
    case wxMOUSE_BTN_LEFT:
      return LeftUp();
    case wxMOUSE_BTN_MIDDLE:
      return MiddleUp();
    case wxMOUSE_BTN_RIGHT:
      return RightUp();
  }
}

bool wxMouseEvent::Button( int but ) const {
  switch( but ) {
    default:
      wxFAIL_MSG( wxT( "invalid parameter in wxMouseEvent::Button" ) );
    // fall through
    case wxMOUSE_BTN_ANY:
      return ButtonUp( wxMOUSE_BTN_ANY ) ||
             ButtonDown( wxMOUSE_BTN_ANY ) ||
             ButtonDClick( wxMOUSE_BTN_ANY );
    case wxMOUSE_BTN_LEFT:
      return LeftDown() || LeftUp() || LeftDClick();
    case wxMOUSE_BTN_MIDDLE:
      return MiddleDown() || MiddleUp() || MiddleDClick();
    case wxMOUSE_BTN_RIGHT:
      return RightDown() || RightUp() || RightDClick();
  }
}

bool wxMouseEvent::ButtonIsDown( int but ) const {
  switch( but ) {
    default:
      wxFAIL_MSG( wxT( "invalid parameter in wxMouseEvent::ButtonIsDown" ) );
    case wxMOUSE_BTN_ANY:
      return LeftIsDown() || MiddleIsDown() || RightIsDown();
    case wxMOUSE_BTN_LEFT:
      return LeftIsDown();
    case wxMOUSE_BTN_MIDDLE:
      return MiddleIsDown();
    case wxMOUSE_BTN_RIGHT:
      return RightIsDown();
  }
}

int wxMouseEvent::GetButton() const {
  for( int i = 1; i <= 3; i++ ) {
    if( Button( i ) ) {
      return i;
    }
  }
  return wxMOUSE_BTN_NONE;
}

wxPoint wxMouseEvent::GetLogicalPosition( const wxDC& dc ) const {
  wxPoint pt( dc.DeviceToLogicalX( m_x ), dc.DeviceToLogicalY( m_y ) );
  return pt;
}

wxKeyEvent::wxKeyEvent( wxEventType type ) {
  m_eventType = type;
  m_shiftDown = false;
  m_controlDown = false;
  m_metaDown = false;
  m_altDown = false;
  m_keyCode = 0;
  m_scanCode = 0;
  m_uniChar = 0;
}

wxKeyEvent::wxKeyEvent( const wxKeyEvent& evt )
  : wxEvent( evt ) {
  m_x = evt.m_x;
  m_y = evt.m_y;
  m_keyCode = evt.m_keyCode;
  m_controlDown = evt.m_controlDown;
  m_shiftDown = evt.m_shiftDown;
  m_altDown = evt.m_altDown;
  m_metaDown = evt.m_metaDown;
  m_scanCode = evt.m_scanCode;
  m_rawCode = evt.m_rawCode;
  m_rawFlags = evt.m_rawFlags;
  m_uniChar = evt.m_uniChar;
}

long wxKeyEvent::KeyCode() const {
  return m_keyCode;
}

wxWindowCreateEvent::wxWindowCreateEvent( wxWindow *win ) {
  SetEventType( wxEVT_CREATE );
  SetEventObject( win );
}

wxWindowDestroyEvent::wxWindowDestroyEvent( wxWindow *win ) {
  SetEventType( wxEVT_DESTROY );
  SetEventObject( win );
}

wxChildFocusEvent::wxChildFocusEvent( wxWindow *win )
  : wxCommandEvent( wxEVT_CHILD_FOCUS ) {
  SetEventObject( win );
}

wxHelpEvent::Origin wxHelpEvent::GuessOrigin( Origin origin ) {
  if( origin == Origin_Unknown ) {
    origin = wxGetKeyState( WXK_F1 ) ? Origin_Keyboard : Origin_HelpButton;
  }
  return origin;
}

#endif

#if wxUSE_BASE

static const int EVENT_TYPE_TABLE_INIT_SIZE = 31;

wxEventHashTable* wxEventHashTable::sm_first = NULL;

wxEventHashTable::wxEventHashTable( const wxEventTable &table )
  : m_table( table ),
    m_rebuildHash( true ) {
  AllocEventTypeTable( EVENT_TYPE_TABLE_INIT_SIZE );
  m_next = sm_first;
  if( m_next ) {
    m_next->m_previous = this;
  }
  sm_first = this;
}

wxEventHashTable::~wxEventHashTable() {
  if( m_next ) {
    m_next->m_previous = m_previous;
  }
  if( m_previous ) {
    m_previous->m_next = m_next;
  }
  if( sm_first == this ) {
    sm_first = m_next;
  }
  Clear();
}

void wxEventHashTable::Clear() {
  size_t i;
  for( i = 0; i < m_size; i++ ) {
    EventTypeTablePointer  eTTnode = m_eventTypeTable[i];
    if( eTTnode ) {
      delete eTTnode;
    }
  }
  if( m_eventTypeTable ) {
    delete[] m_eventTypeTable;
  }
  m_eventTypeTable = NULL;
  m_size = 0;
}

// Clear all tables
void wxEventHashTable::ClearAll() {
  wxEventHashTable* table = sm_first;
  while( table ) {
    table->Clear();
    table = table->m_next;
  }
}

// Rebuild all tables if they were cleared by ClearAll
void wxEventHashTable::ReconstructAll() {
  wxEventHashTable* table = sm_first;
  while( table ) {
    if( table->m_eventTypeTable == NULL ) {
      table->AllocEventTypeTable( EVENT_TYPE_TABLE_INIT_SIZE );
      table->m_rebuildHash = true;
    }
    table = table->m_next;
  }
}

bool wxEventHashTable::HandleEvent( wxEvent &event, wxEvtHandler *self ) {
  if( m_rebuildHash ) {
    InitHashTable();
    m_rebuildHash = false;
  }
  if( !m_eventTypeTable ) {
    return false;
  }
  // Find all entries for the given event type.
  wxEventType eventType = event.GetEventType();
  const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size];
  if( eTTnode && eTTnode->eventType == eventType ) {
    // Now start the search for an event handler
    // that can handle an event with the given ID.
    const wxEventTableEntryPointerArray&
    eventEntryTable = eTTnode->eventEntryTable;
    const size_t count = eventEntryTable.GetCount();
    for( size_t n = 0; n < count; n++ ) {
      if( wxEvtHandler::
          ProcessEventIfMatches( *eventEntryTable[n], self, event ) ) {
        return true;
      }
    }
  }
  return false;
}

void wxEventHashTable::InitHashTable() {
  // Loop over the event tables and all its base tables.
  const wxEventTable *table = &m_table;
  while( table ) {
    // Retrieve all valid event handler entries
    const wxEventTableEntry *entry = table->entries;
    while( entry->m_fn != 0 ) {
      // Add the event entry in the Hash.
      AddEntry( *entry );
      entry++;
    }
    table = table->baseTable;
  }
  // Lets free some memory.
  size_t i;
  for( i = 0; i < m_size; i++ ) {
    EventTypeTablePointer  eTTnode = m_eventTypeTable[i];
    if( eTTnode ) {
      eTTnode->eventEntryTable.Shrink();
    }
  }
}

void wxEventHashTable::AddEntry( const wxEventTableEntry &entry ) {
  // This might happen 'accidentally' as the app is exiting
  if( !m_eventTypeTable ) {
    return;
  }
  EventTypeTablePointer *peTTnode = &m_eventTypeTable[entry.m_eventType % m_size];
  EventTypeTablePointer  eTTnode = *peTTnode;
  if( eTTnode ) {
    if( eTTnode->eventType != entry.m_eventType ) {
      // Resize the table!
      GrowEventTypeTable();
      // Try again to add it.
      AddEntry( entry );
      return;
    }
  } else {
    eTTnode = new EventTypeTable;
    eTTnode->eventType = entry.m_eventType;
    *peTTnode = eTTnode;
  }
  // Fill all hash entries between entry.m_id and entry.m_lastId...
  eTTnode->eventEntryTable.Add( &entry );
}

void wxEventHashTable::AllocEventTypeTable( size_t size ) {
  m_eventTypeTable = new EventTypeTablePointer[size];
  memset( ( void * )m_eventTypeTable, 0, sizeof( EventTypeTablePointer )*size );
  m_size = size;
}

void wxEventHashTable::GrowEventTypeTable() {
  size_t oldSize = m_size;
  EventTypeTablePointer *oldEventTypeTable = m_eventTypeTable;
  AllocEventTypeTable( /* GetNextPrime(oldSize) */oldSize * 2 + 1 );
  for( size_t i = 0; i < oldSize; /* */ ) {
    EventTypeTablePointer  eTToldNode = oldEventTypeTable[i];
    if( eTToldNode ) {
      EventTypeTablePointer *peTTnode = &m_eventTypeTable[eTToldNode->eventType % m_size];
      EventTypeTablePointer  eTTnode = *peTTnode;
      // Check for collision, we don't want any.
      if( eTTnode ) {
        GrowEventTypeTable();
        continue; // Don't increment the counter,
        // as we still need to add this element.
      } else {
        // Get the old value and put it in the new table.
        *peTTnode = oldEventTypeTable[i];
      }
    }
    i++;
  }
  delete[] oldEventTypeTable;
}

wxEvtHandler::wxEvtHandler() {
  m_nextHandler = ( wxEvtHandler * ) NULL;
  m_previousHandler = ( wxEvtHandler * ) NULL;
  m_enabled = true;
  m_dynamicEvents = ( wxList * ) NULL;
  m_pendingEvents = ( wxList * ) NULL;
  #if wxUSE_THREADS
  #  if !defined(__VISAGECPP__)
  m_eventsLocker = new wxCriticalSection;
  #  endif
  #endif
  // no client data (yet)
  m_clientData = NULL;
  m_clientDataType = wxClientData_None;
}

wxEvtHandler::~wxEvtHandler() {
  // Takes itself out of the list of handlers
  if( m_previousHandler ) {
    m_previousHandler->m_nextHandler = m_nextHandler;
  }
  if( m_nextHandler ) {
    m_nextHandler->m_previousHandler = m_previousHandler;
  }
  if( m_dynamicEvents ) {
    for( wxList::iterator it = m_dynamicEvents->begin(),end = m_dynamicEvents->end();it != end;++it ) {
      wxDynamicEventTableEntry *entry = ( wxDynamicEventTableEntry* )*it;
      if( entry->m_callbackUserData ) {
        delete entry->m_callbackUserData;
      }
      delete entry;
    }
    delete m_dynamicEvents;
  };
  if( m_pendingEvents ) {
    m_pendingEvents->DeleteContents( true );
  }
  delete m_pendingEvents;
  #if wxUSE_THREADS
  #  if !defined(__VISAGECPP__)
  delete m_eventsLocker;
  #  endif
  // Remove us from wxPendingEvents if necessary.
  if( wxPendingEventsLocker ) {
    wxENTER_CRIT_SECT( *wxPendingEventsLocker );
  }
  #endif // wxUSE_THREADS
  if( wxPendingEvents ) {
    // Delete all occurences of this from the list of pending events
    while( wxPendingEvents->DeleteObject( this ) ) { } // Do nothing
  }
  #if wxUSE_THREADS
  if( wxPendingEventsLocker ) {
    wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
  }
  #endif // wxUSE_THREADS
  // we only delete object data, not untyped
  if( m_clientDataType == wxClientData_Object ) {
    delete m_clientObject;
  }
}

#if wxUSE_THREADS

bool wxEvtHandler::ProcessThreadEvent( wxEvent& event ) {
  // check that we are really in a child thread
  wxASSERT_MSG( !wxThread::IsMain(),
                wxT( "use ProcessEvent() in main thread" ) );
  AddPendingEvent( event );
  return true;
}

void wxEvtHandler::ClearEventLocker() {
  #if !defined(__VISAGECPP__)
  delete m_eventsLocker;
  m_eventsLocker = NULL;
  #endif
}

#endif // wxUSE_THREADS

void wxEvtHandler::AddPendingEvent( wxEvent& event ) {
  // 1) Add event to list of pending events of this event handler
  wxEvent *eventCopy = event.Clone();
  // we must be able to copy the events here so the event class must
  // implement Clone() properly instead of just providing a NULL stab for it
  wxCHECK_RET( eventCopy,
               _T( "events of this type aren't supposed to be posted" ) );
  wxENTER_CRIT_SECT( Lock() );
  if( !m_pendingEvents ) {
    m_pendingEvents = new wxList;
  }
  m_pendingEvents->Append( eventCopy );
  // 2) Add this event handler to list of event handlers that
  //    have pending events.
  wxENTER_CRIT_SECT( *wxPendingEventsLocker );
  if( !wxPendingEvents ) {
    wxPendingEvents = new wxList;
  }
  wxPendingEvents->Append( this );
  wxLEAVE_CRIT_SECT( *wxPendingEventsLocker );
  wxLEAVE_CRIT_SECT( Lock() );
  // 3) Inform the system that new pending events are somewhere,
  //    and that these should be processed in idle time.
  wxWakeUpIdle();
}

void wxEvtHandler::ProcessPendingEvents() {
  // this method is only called by wxApp if this handler does have
  // pending events
  wxCHECK_RET( m_pendingEvents,
               wxT( "Please call wxApp::ProcessPendingEvents() instead" ) );
  wxENTER_CRIT_SECT( Lock() );
  size_t n = m_pendingEvents->size();
  for( wxList::compatibility_iterator node = m_pendingEvents->GetFirst();
       node;
       node = m_pendingEvents->GetFirst() ) {
    {
      wxEventPtr event( wx_static_cast( wxEvent *, node->GetData() ) );
      m_pendingEvents->Erase( node );
      wxLEAVE_CRIT_SECT( Lock() );
      ProcessEvent( *event );
    }
    wxENTER_CRIT_SECT( Lock() );
    if( --n == 0 ) {
      break;
    }
  }
  wxLEAVE_CRIT_SECT( Lock() );
}

bool wxEvtHandler::ProcessEventIfMatches( const wxEventTableEntryBase& entry,
    wxEvtHandler *handler,
    wxEvent& event ) {
  int tableId1 = entry.m_id,
      tableId2 = entry.m_lastId;
  if( ( tableId1 == wxID_ANY ) ||
      ( tableId2 == wxID_ANY && tableId1 == event.GetId() ) ||
      ( tableId2 != wxID_ANY &&
        ( event.GetId() >= tableId1 && event.GetId() <= tableId2 ) ) ) {
    event.Skip( false );
    event.m_callbackUserData = entry.m_callbackUserData;
    #if wxUSE_EXCEPTIONS
    if( wxTheApp ) {
      wxTheApp->HandleEvent( handler, ( wxEventFunction )entry.m_fn, event );
    } else
    #endif // wxUSE_EXCEPTIONS
    {
      ( handler->*( ( wxEventFunction )( entry.m_fn ) ) )( event );
    }
    if( !event.GetSkipped() ) {
      return true;
    }
  }
  return false;
}

bool wxEvtHandler::TryParent( wxEvent& event ) {
  if( wxTheApp && ( this != wxTheApp ) ) {
    if( event.GetEventType() != wxEVT_IDLE ) {
      if( wxTheApp->ProcessEvent( event ) ) {
        return true;
      }
    }
  }
  return false;
}

bool wxEvtHandler::ProcessEvent( wxEvent& event ) {
  if( wxTheApp ) {
    int rc = wxTheApp->FilterEvent( event );
    if( rc != -1 ) {
      wxASSERT_MSG( rc == 1 || rc == 0, _T( "unexpected wxApp::FilterEvent return value" ) );
      return rc != 0;
    }
    //else: proceed normally
  }
  // An event handler can be enabled or disabled
  if( GetEvtHandlerEnabled() ) {
    // if we have a validator, it has higher priority than our own event
    // table
    if( TryValidator( event ) ) {
      return true;
    }
    // Handle per-instance dynamic event tables first
    if( m_dynamicEvents && SearchDynamicEventTable( event ) ) {
      return true;
    }
    // Then static per-class event tables
    if( GetEventHashTable().HandleEvent( event, this ) ) {
      return true;
    }
  }
  // Try going down the event handler chain
  if( GetNextHandler() ) {
    if( GetNextHandler()->ProcessEvent( event ) ) {
      return true;
    }
  }
  // Finally propagate the event upwards the window chain and/or to the
  // application object as necessary
  return TryParent( event );
}


bool wxEvtHandler::SearchEventTable( wxEventTable& table, wxEvent& event ) {
  const wxEventType eventType = event.GetEventType();
  for( int i = 0; table.entries[i].m_fn != 0; i++ ) {
    const wxEventTableEntry& entry = table.entries[i];
    if( eventType == entry.m_eventType ) {
      if( ProcessEventIfMatches( entry, this, event ) ) {
        return true;
      }
    }
  }
  return false;
}

void wxEvtHandler::Connect( int id, int lastId,
                            int eventType,
                            wxObjectEventFunction func,
                            wxObject *userData,
                            wxEvtHandler* eventSink ) {
  wxDynamicEventTableEntry *entry =new wxDynamicEventTableEntry( eventType, id, lastId, func, userData, eventSink );
  if( !m_dynamicEvents ) {
    m_dynamicEvents = new wxList;
  }
  m_dynamicEvents->Insert( ( wxObject* ) entry );
}

bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType,
                               wxObjectEventFunction func,
                               wxObject *userData,
                               wxEvtHandler* eventSink ) {
  if( !m_dynamicEvents ) {
    return false;
  }
  wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
  while( node ) {
    wxDynamicEventTableEntry *entry = ( wxDynamicEventTableEntry* )node->GetData();
    if( ( entry->m_id == id ) &&
        ( ( entry->m_lastId == lastId ) || ( lastId == wxID_ANY ) ) &&
        ( ( entry->m_eventType == eventType ) || ( eventType == wxEVT_NULL ) ) &&
        ( ( entry->m_fn == func ) || ( func == ( wxObjectEventFunction )NULL ) ) &&
        ( ( entry->m_eventSink == eventSink ) || ( eventSink == ( wxEvtHandler* )NULL ) ) &&
        ( ( entry->m_callbackUserData == userData ) || ( userData == ( wxObject* )NULL ) ) ) {
      if( entry->m_callbackUserData ) {
        delete entry->m_callbackUserData;
      }
      m_dynamicEvents->Erase( node );
      delete entry;
      return true;
    }
    node = node->GetNext();
  }
  return false;
}

bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event ) {
  wxCHECK_MSG( m_dynamicEvents, false, wxT( "调用方应检查是否有动态事件" ) );
  wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
  while( node ) {
    wxDynamicEventTableEntry *entry = ( wxDynamicEventTableEntry* )node->GetData();
    node = node->GetNext();
    if( ( event.GetEventType() == entry->m_eventType ) && ( entry->m_fn != 0 ) ) {
      wxEvtHandler *handler =
        #if !WXWIN_COMPATIBILITY_EVENT_TYPES
        entry->m_eventSink ? entry->m_eventSink
        :
        #endif
        this;
      if( ProcessEventIfMatches( *entry, handler, event ) ) {
        return true;
      }
    }
  }
  return false;
}

void wxEvtHandler::DoSetClientObject( wxClientData *data ) {
  wxASSERT_MSG( m_clientDataType != wxClientData_Void, wxT( "不能同时拥有对象和无效客户端数据" ) );
  if( m_clientObject ) {
    delete m_clientObject;
  }
  m_clientObject = data;
  m_clientDataType = wxClientData_Object;
}

wxClientData *wxEvtHandler::DoGetClientObject() const {
  wxASSERT_MSG( m_clientDataType != wxClientData_Void, wxT( "此窗口没有对象客户端数据" ) );
  return m_clientObject;
}

void wxEvtHandler::DoSetClientData( void *data ) {
  wxASSERT_MSG( m_clientDataType != wxClientData_Object, wxT( "不能同时拥有对象和无效客户端数据" ) );
  m_clientData = data;
  m_clientDataType = wxClientData_Void;
}

void *wxEvtHandler::DoGetClientData() const {
  wxASSERT_MSG( m_clientDataType != wxClientData_Object, wxT( "此窗口没有void客户端数据" ) );
  return m_clientData;
}

#endif // wxUSE_BASE

#if wxUSE_GUI

wxWindow* wxFindFocusDescendant( wxWindow* ancestor ) {
  wxWindow* focusWin = wxWindow::FindFocus();
  wxWindow* win = focusWin;
  while( win ) {
    if( win == ancestor ) {
      break;
    } else {
      win = win->GetParent();
    }
  }
  if( win == ( wxWindow* ) NULL ) {
    focusWin = ( wxWindow* ) NULL;
  }
  return focusWin;
}

#endif
